﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Solidi
{
	/// <summary>
	/// Thread safe
	/// </summary>
	public sealed class ListDependencyRegistry : IDependencyRegistry
	{
		private IDependencyRegistry _registry;

		public ListDependencyRegistry(IDependencyRegistry registry)
		{
			if (registry == null)
			{
				throw new ArgumentNullException("registry");
			}

			_registry = registry;
		}

		public void Add(IEnumerable<IDependency> dependencies)
		{
			_registry.Add(dependencies);
		}

		public IEnumerable<IDependency> Find(IDependencyKey key, Func<IEnumerable<IDependency>> dependencyFactory = null)
		{
            if (key == null)
            {
                throw new ArgumentNullException("key");
            }

			Type type = key.Type;

			if (type.IsGenericType)
			{
				Type genericType = type.GetGenericTypeDefinition();

				if (genericType == typeof(IList<>) || genericType == typeof(IEnumerable<>) || genericType == typeof(ICollection<>))
				{
					return _registry.Find(key, () => 
					{
						Type itemType = type.GetGenericArguments()[0];

						Func<IDependencyContainer, object>  factory = (c) =>
						{
							IList instances = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(itemType));

							foreach (IDependency dependency in c.Registry.Find(new DependencyKey(itemType, key.Name), null))
							{
								object instance;

								if (c.Lifetime.TryAcquire(c, dependency, out instance))
								{
									instances.Add(instance);
								}
							}

							if (instances.Count > 0)
							{
								return instances;
							}

							return null;
						};

						return new IDependency[] { new ListDependency(factory, key) };
					});
				}
			}

			return _registry.Find(key, dependencyFactory);
		}
	}
}
